package cn.tit.ias.aop;

import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.apache.log4j.Logger;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;


import cn.tit.ias.entity.SystemLogInfo;
import cn.tit.ias.entity.UserInfo;
import cn.tit.ias.service.DicUserRoleInfoService;
import cn.tit.ias.service.SystemLogService;
import cn.tit.ias.service.UserInfoService;

@Aspect
@Component
public class UserOperationsLogging {

	private Logger logger = Logger.getLogger(UserOperationsLogging.class);

	public static UserInfo user = new UserInfo();
	@Autowired
	SystemLogService systemLogService;
	@Autowired
	DicUserRoleInfoService roleInfoService;
	@Autowired
	UserInfoService userInfoService;
	@Autowired
	HttpServletRequest request; // 这里可以获取到request
	Date date = new Date();
	@Pointcut("@annotation(cn.tit.ias.aop.MethodLog)")
	public void method() {

	}
	
	// 用来做环绕通知的方法可以第一个参数定义为org.aspectj.lang.ProceedingJoinPoint类型
	@Around("method()")
	public Object around(ProceedingJoinPoint call) throws Throwable {
		Object result = null;

		// 取得类名和方法名
		String className = call.getTarget().getClass().getName();
		String methodName = call.getSignature().getName();
		System.out.println("环绕通知");
		// 相当于前置通知
		String logStr = className + "类的" + methodName + "方法开始执行******Start******";
		logger.info(logStr);

		try {
			result = call.proceed();
			// 相当于后置通知
			logStr = className + "." + methodName + "()方法正常执行结束...";
			logger.info(logStr);

		} catch (Throwable e) {
			// 相当于异常抛出后通知
			StackTraceElement stackTraceElement = e.getStackTrace()[e.getStackTrace().length - 1];

			Object[] args = call.getArgs();

			logger.error("----------------------------------------------------------------------------------");
			logger.error(className + "类的" + methodName + "方法" + stackTraceElement.getLineNumber());
			//logger.error(e.fillInStackTrace().toString());
			logger.error(args);
			throw e;

		} finally {
			// 相当于最终通知
			logStr = className + "类的" + methodName + "方法执行结束******End******";
			logger.info(logStr);
		}

		return result;
	}
	/**
	 * 
	 * @Title: loginBefore   
	 * @Description: 用户退出登陆记录
	 * @param: @param point      
	 * @return: void      
	 * @throws
	 */
	@Before("execution(* cn.tit.ias.controller.pc.PCUserInfoController.logout(..))")
	public void loginBefore(JoinPoint point) {
		Subject subject = SecurityUtils.getSubject();
		Session session = subject.getSession();
		UserInfo loginUser = (UserInfo) session.getAttribute("loginUser");
		String ip = (String) session.getAttribute("ip");
		Map<String, Object> record = new HashMap<String, Object>();
		if (loginUser != null) {
			record.put("userCount", loginUser.getUserCount());
			record.put("userName", loginUser.getUserName());
			record.put("accessType", "logout");
			record.put("accessIp", ip);
			record.put("departNum", loginUser.getDepartNum());
			record.put("accessTime", date);
			// 保存日志
			systemLogService.insertLoginRecord(record);
		}

	}

	/**
	 * 
	 * @Title: after   
	 * @Description: 用户操作 记录 
	 * @param: @param joinpoint
	 * @param: @throws ClassNotFoundException      
	 * @return: void      
	 * @throws
	 */
	@AfterReturning("method()")
	public void after(JoinPoint joinpoint) throws ClassNotFoundException {
		System.err.println("this is after.................");

		// 获取shiro的session域中登陆的用户
		Subject subject =  SecurityUtils.getSubject();
		Session session = subject.getSession();
		String ip = (String) session.getAttribute("ip");
		UserInfo user = (UserInfo)session.getAttribute("loginUser");
		if(user != null){
			String userRole = (String) session.getAttribute("loginUserRole");
			
			// 将用户操作写入日志数据库
			System.out.println(getMethodDesc(joinpoint).getOperation());
			if(getMethodDesc(joinpoint).getOperation().equals("登陆")){
				Map<String, Object> record = new HashMap<String, Object>();
				if(user.getUserCount() != null || user.getUserCount() != ""){
					record.put("userCount", user.getUserCount());
					record.put("userName", user.getUserName());
					record.put("accessType", "login");
					record.put("accessIp", ip);
					record.put("departNum", user.getDepartNum());
					record.put("accessTime", date);
					systemLogService.insertLoginRecord(record);
				}else{
					System.out.println("用户未登陆");
				}
			}else{
				System.out.println(getMethodDesc(joinpoint).getOperation());
				SystemLogInfo logInfo = new SystemLogInfo();
				logInfo.setUserCount(user.getUserCount());
				logInfo.setCreateTime(date);
				logInfo.setIp(ip);
				logInfo.setOperation(getMethodDesc(joinpoint).getOperation());
				logInfo.setContent(getMethodDesc(joinpoint).getContent());
				logInfo.setUserName(user.getUserName());
				logInfo.setDepartNum(user.getDepartNum());
				logInfo.setUserRole(userRole);
				System.out.println(logInfo);
				systemLogService.insert(logInfo);
			}
			// 写入日志文件
			String methodName = joinpoint.getSignature().getName();
			String className = joinpoint.getTarget().getClass().getName();
			String logStr = className + "类的" + methodName + "方法执行完毕";
			logger.info(logStr);
		}
		
	}
	/**
	 * 
	 * @Title: getMethodDesc   
	 * @Description: 获取用户操作的模块和内容
	 * @param: @param joinPoint
	 * @param: @return
	 * @param: @throws ClassNotFoundException      
	 * @return: SystemLogInfo      
	 * @throws
	 */
	public static SystemLogInfo getMethodDesc(JoinPoint joinPoint) throws ClassNotFoundException {
		String targetName = joinPoint.getTarget().getClass().getName();
		String methodName = joinPoint.getSignature().getName();
		Object[] arguments = joinPoint.getArgs();
		Class targetClass = Class.forName(targetName);
		Method[] methods = targetClass.getMethods();
		String operteContent = "";
		String operation = "";
		for (Method method : methods) {
			if (method.getName().equals(methodName)) {
				Class[] clazzs = method.getParameterTypes();
				if (clazzs.length == arguments.length) {
					// 操作说明
					operteContent = method.getAnnotation(MethodLog.class).name();
					operation = method.getAnnotation(MethodLog.class).option();
					break;
				}
			}
		}
		SystemLogInfo logInfo = new SystemLogInfo();
		logInfo.setContent(operteContent);
		logInfo.setOperation(operation);
		return logInfo;
	}

}
